﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Othello
{
    public class Board
    {
        public const int Size = 8;
        public const int SelfFlag = 0xff;
        public const int BoardFlag = 0xffff;
        public const int PointFlag = 0x101;

        private int[] rows = new int[8];
        private int[] moveableRowPoints = new int[8];

        public Board()
        {
            Initlize();
        }

        public void Initlize()
        {
            for (int i = 0; i < Size; i++)
            {
                rows[i] = 0;
            }
            rows[3] =  1 << 4;
            rows[4] = 3 << 3 << Size;
            CalMoveablePlaces();
        }

        public Piece GetPoint(int x, int y)
        {
            if (((moveableRowPoints[y] >> x) & 1) != 0) return Piece.Moveable;
            else if (((rows[y] >> x) & 1) != 0) return Piece.Self;
            else if (((rows[y] >> x >> Size) & 1) != 0) return Piece.Other;
            else return Piece.None;
        }

        public void PutDown(int x, int y)
        {
            int r1 = 0;
            int r2 = 0;
            int r3 = 0;
            rows[y] = OthelloUtil.PutDown(rows[y], x);
            for (int j = 0; j < Size; j++)
            {
                r1 |= ((rows[j] >> x) & PointFlag) << j;
            }

            int a2 = Math.Max(0, y - x);
            int b2 = Math.Min(Size, Size + y - x);
            int a3 = Math.Max(0, y + x + 1 - Size);
            int b3 = Math.Min(Size, y + x + 1);

            for (int j = a2; j < b2; j++)
            {
                r2 |= ((rows[j] >> (j - a2)) & PointFlag) << j;
            }

            for (int j = a3; j < b3; j++)
            {
                r3 |= ((rows[j] >> (Size - 1 - j + a3)) & PointFlag) << j;
            }

            r1 = OthelloUtil.PutDown(r1, y);
            r2 = OthelloUtil.PutDown(r2, a2 + y);
            r3 = OthelloUtil.PutDown(r3, a3 + Size - 1 - y);

            for (int j = 0; j < Size; j++)
            {
                rows[j] &= ~(PointFlag << x);
                rows[j] |= ((r1 >> j) & PointFlag) << x;
            }

            for (int j = a2; j < b2; j++)
            {
                rows[j] &= ~(PointFlag << (j - a2));
                rows[j] |= ((r2 >> j) & PointFlag) << (j - a2);
            }

            for (int j = a3; j < b3; j++)
            {
                rows[j] &= ~(PointFlag << (Size - 1 - j + a3));
                rows[j] |= ((r2 >> j) & PointFlag) << (Size - 1 - j + a3);
            }

            CalMoveablePlaces();
        }

        private void CalMoveablePlaces()
        {
            int p1, p2, p3, p4, p5, m1, m2, m3, m4, m5;
            for (int i = 0; i < Size; i++)
            {
                moveableRowPoints[i] = OthelloUtil.GetMoveablePlaces(rows[i]);
            }
            for (int i = 0; i < Size; i++)
            {
                p1 = p2 = p3 = p4 = p5 = 0;
                for (int j = 0; j < Size; j++)
                {
                    p1 |= ((rows[j] >> i) & PointFlag) << j;

                }

                for (int j = 0; j < Size - i; j++)
                {
                    p2 |= ((rows[j] >> (i + j)) & PointFlag) << j;
                    p3 |= ((rows[i + j] >> j) & PointFlag) << j;
                }

                for (int j = 0; j <= i; j++)
                {
                    p4 |= ((rows[j] >> (i - j)) & PointFlag) << j;
                    p5 |= ((rows[Size - 1 - i + j] >> (Size - 1 - j)) & PointFlag) << j;
                }

                m1 = OthelloUtil.GetMoveablePlaces(p1);
                m2 = OthelloUtil.GetMoveablePlaces(p2);
                m3 = OthelloUtil.GetMoveablePlaces(p3);
                m4 = OthelloUtil.GetMoveablePlaces(p4);
                m5 = OthelloUtil.GetMoveablePlaces(p5);

                for (int j = 0; j < Size; j++)
                {
                    moveableRowPoints[j] |= ((m1 >> j) & 1) << i;
                }

                for (int j = 0; j < Size - i; j++)
                {
                    moveableRowPoints[j] |= ((m2 >> j) & 1) << (i + j);
                    moveableRowPoints[i + j] |= ((m3 >> j) & 1) << j;
                }

                for (int j = 0; j <= i; j++)
                {
                    moveableRowPoints[j] |= ((m4 >> j) & 1) << (i - j);
                    moveableRowPoints[Size - 1 - i + j] |= ((m5 >> j) & 1) << (Size - 1 - j);
                }
            }
        }

        public Piece[,] GetAllPoints()
        {
            Piece[,] points = new Piece[8, 8];
            for (int i = 0; i < Size; i++)
            {
                for (int j = 0; j < Size; j++)
                {
                    points[i, j] = GetPoint(i, j);
                }
            }
            return points;
        }

        public void Reverse()
        {
            for (int i = 0; i < Size; i++)
            {
                rows[i] = (rows[i] >> Size | rows[i] << Size) & Board.BoardFlag;
            }
            CalMoveablePlaces();
        }
    }

    public enum Piece
    {
        None = 0,
        Self = 1,
        Other = 2,
        Moveable = 3
    }

    public static class OthelloUtil
    {
        private static Dictionary<int, int> rowScores = new Dictionary<int, int>();

        public static int Reverse(int row)
        {
            return (row >> Board.Size | row << Board.Size) & Board.BoardFlag;
        }

        public static int GetScore(Board board)
        {
            return 0;
        }

        public static int GetMoveablePlaces(int row)
        {
            int self = row & Board.SelfFlag;
            int other = (row >> Board.Size) & Board.SelfFlag;
            int currentPlaces = self | other;
            int emptyPlaces = Board.SelfFlag & ~currentPlaces;
            int mixPlaces = self;
            for (int i = 0; i < Board.Size; i++)
            {
                mixPlaces |= (mixPlaces << 1 & other) | (mixPlaces >> 1 & other);
            }
            int otherMixPlaces = other & mixPlaces;
            int moveablePlaces = (otherMixPlaces << 1 | otherMixPlaces >> 1) & emptyPlaces;
            return moveablePlaces;
        }

        public static int PutDown(int row, int place)
        {
            int self = row & Board.SelfFlag;
            int other = (row >> Board.Size) & Board.SelfFlag;
            int placesToTurn = 1 << place;

            self |= placesToTurn;

            int i;
            for (i = place + 1; (1 << i & other) != 0 && i < Board.Size; i++)
            {
                placesToTurn |= 1 << i & other;
            }
            if ((1 & self >> i) != 0)
            {
                other &= ~placesToTurn;
                self |= placesToTurn;
            }

            placesToTurn = 1 << place;
            for (i = place - 1; (1 << i & other) != 0 && i >= 0; i--)
            {
                placesToTurn |= 1 << i & other;
            }
            if ((1 & self >> i) != 0)
            {
                other &= ~placesToTurn;
                self |= placesToTurn;
            }

            return other << Board.Size | self;
        }

        public static int GetScore(int row)
        {
            return rowScores[row];
        }
    }
}
